#! /usr/bin/python
import color
import curses
from string import lower
import textwrap
from os import system
import logging

__author__="simon"
__date__ ="$Feb 14, 2010 4:17:49 PM$"

class Box(object):
    def __init__(self,name,y0,x0,y1,x1,border="default"):
        self.reSize(y0, x0, y1, x1) #the first reSize creates the window/pad objs
        self.name = name
        self.borderSetting = border

    def reSize(self,y0,x0,y1,x1):
        self.screen = curses.newwin(y1-y0,x1-x0,y0,x0)
        self.sub = self.screen.derwin(y1-y0-1, x1-x0-1, y0-1, x0-1)
        self.screen.pos = [(y0,x0),(y1,x1)]
        self.sub.pos = [(y0-1,x0-1),(y1-1,x1-1)]

    def border(self):
        if self.borderSetting == "default":
            self.screen.box()
        elif self.borderSetting == None:
            pass # draw no border
        else:
            self.screen.border(self.borderSetting)

    def size(self):
        pos = self.sub.pos
        pos0,pos1 = pos[0],pos[1]
        return (pos0[0]-pos1[0],pos0[1]-pos1[1])

    def sizeBox(self):
        pos = self.screen.pos
        pos0,pos1 = pos[0],pos[1]
        return (pos0[0]-pos1[0],pos0[1]-pos1[1])

    def __str__(self):
        return "%s, (%d,%d) - (%d,%d)" % self.name,self.y0,self.x0,self.y1,self.x1

    def addstr(self,y,x,text,colordesc):
        if colordesc:
            code = color.make_attr(colordesc)
            self.screen.addstr(y,x,text,code)
        else:
            self.screen.addstr(y,x,text)

    def clear(self):
        self.screen.clear()

    def refresh(self):
        self.screen.refresh()

class BuddyList(Box):
    def __init__(self,*args):
        Box.__init__(self,*args)
        self.buddies = {}
        self.buddyNames = []
        self.scrollPos = 0

    def addBuddy(self,buddyName,buddyInfo):
        self.buddies[buddyName] = buddyInfo
        self.buddyNames += [buddyName]
        self.reDraw()

    def removeBuddy(self,buddyName):
        if buddyName in self.buddies:
            del self.buddies[buddyName]
        if buddyName in self.buddyNames:
            self.buddyNames.remove(buddyName)
        self.reDraw()

    def reDraw(self):
        self.screen.clear()
        self.border()
        yMax,xMax = self.size()[0] -1,self.size()[1] -1
        numBuddies = len(self.buddyNames)
        scrollEnd = min(yMax + self.scrollPos,numBuddies)
        y,x = 1,1
        if self.scrollPos > 0:
            self.addstr(y,x,"...","blue")
            y +=1
        for name in self.buddyNames[self.scrollPos:scrollEnd]:
            if len(name) > xMax:  #truncate the string
                name = name[0:xMax]
            if y == yMax and name != self.buddyNames[-1]:
                self.addstr(y,x,"...","blue")
                break
            self.addstr(y, x, name, colordesc="green")
            y+=1
        self.refresh()

    def scroll(self,lines):
        if lines == 0: return
        self.scrollPos = max(0,self.scrollPos + lines)
        self.scrollPos = min(len(self.buddyNames) - self.size()[0] + 2,self.scrollPos)
        if self.scrollPos == 1 and lines == 1:
            self.scrollPos = 2
        self.reDraw()

class Message():
    def __init__(self,text,sender):
        self.text = text
        self.sender = sender

class MainTextBox(Box):
    def __init__(self,*args):
        Box.__init__(self,*args)
        #wrap text 2 characters less than the number of columns
        self.textwrap = textwrap.TextWrapper(self.size()[1] - 2)
        self.messages = []
        self.text = []
        self.offset = 0
        self.vBottom = self.size()[0]
        
    def addMessage(self,message):
        text = self.formatMessage(message)
        numLines = len(text)
        if self.vBottom == len(self.text):
            self.vBottom += numLines
        self.messages += [message]
        self.text += text
        self.reDraw()

    def scroll(self,lines):
        vBottom = max(0,self.vBottom + lines)
        vBottom = min(vBottom,len(self.text))
        self.vBottom = max(vBottom,self.size()[0]-1)
        self.reDraw()

    def formatMessage(self,message):
        text = message.sender + ": " + message.text
        textWrapped = self.textwrap.wrap(text)
        return textWrapped

    def reDraw(self):
        self.clear()
        self.border()
        yMax,xMax = self.size()[0] -1,self.size()[1] -1
        textmax = len(self.text)
        bottomLine = min(self.vBottom,len(self.text))
        topLine = max(0,bottomLine - yMax)
        y,x = 1,1
        for line in self.text[topLine:bottomLine]:
            self.addstr(y,x,line,"white")
            y +=1
        self.refresh()

class ChatInput(Box):
    def __init__(self,*args):
        Box.__init__(self,*args)
        self.text = []
        self.addLines(5)
        self.textwrap = textwrap.TextWrapper(self.size()[1] - 2)
        self.cursorPos = [1,1]
        self.topLine = 0
        self.cursor = "_"
        logging.debug("Here is self.text in ChatInput: " + repr(self.text))

    def moveCursor(self,dir):
        status = 0 #record if the cursor moved
        sign = 1   #default to down/right
        var = 0    #default to up or down (y coordinate)
        if dir == "l" or dir == "r":
            var = 1
        if dir == "u" or dir == "l":
            sign = -1
        size = self.size()[var]
        if sign == 1:
            if self.cursorPos[var] < size -1:status = 1
        else:
            if self.cursorPos[var] > 1:status =1
        if status:self.cursorPos[var] += sign
        self.reDraw()
        return status
        
    def addLines(self,numLines):
        for num in xrange(0,numLines):
            line = [" " for x in xrange(0,self.size()[1] -2)]
            self.text += [line]
    
    def addText(self,ch):
        lineDifference = self.topLine + (self.cursorPos[0] -1) - len(self.text)
        if lineDifference > 0:
            self.addLines(lineDifference)
        editLine = self.text[self.topLine + self.cursorPos[0]-1]
        logging.debug("editLine is:" + repr(editLine))
        editLine.insert(self.cursorPos[1],ch)
        textList =  self.textwrap.wrap("".join(["".join(x) for x in self.text]))
        self.text = [[character for character in eachStr]
                    for eachStr in [eachStr for eachStr in textList]]


    def reDraw(self):
        self.clear()
        self.border()
        #self.addstr(self.cursorPos[0],self.cursorPos[1],self.cursor, colordesc="bold:white")
        self.screen.move(self.cursorPos[0],self.cursorPos[1])
        self.refresh()

def test(stdscr):
    LOG_FILENAME = './logging_example.out'
    logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
    logging.debug('pyquickchatroom')


    color.setup_colors()
    curses.noecho()
    curses.curs_set(1)
    curses.curs_set(1)
    names = ["Top","Matt","Lindsey","Test","Silver","Slinky","Mithril","Chirp",
            "ReallyFuckingLongAssTestStringYo","Other","Silly","Names","To",
            "Test","Out","This","Code","Damn","I","Still","Need","More",
            "Lines","To","testout","My","Max","Rows","Bottom"]
    box = BuddyList("Buddy List",0,50,20,80)
    chat = MainTextBox("MainMessagesWindow",0,0,20,50)
    chat.reDraw()
    inputBox = ChatInput("Chatty",21,0,26,80)
    inputBox.reDraw()
    for name in names:
        box.addBuddy(name, None)
        curses.delay_output(100)
        message = Message(name,name)
        chat.addMessage(message)
    #box.reSize(0,45,22,80)
    i = 1
    j = -1
    while(1):
        break
        box.scroll(i)
        chat.scroll(j)
        curses.delay_output(250)
        if box.scrollPos == len(box.buddyNames) - box.size()[0] + 3 or box.scrollPos == 0:
            i = -1 * i
            curses.delay_output(150)
        if chat.vBottom < chat.size()[0] or chat.vBottom >= len(chat.text):
            j = -1 * j
    while(1):
        command = inputBox.screen.getch()
        if command == curses.KEY_NPAGE:
            box.scroll(-1)
        if command == curses.KEY_PPAGE:
            box.scroll(1)
        if command == curses.KEY_HOME:
            chat.scroll(-1)
        if command == curses.KEY_END:
            chat.scroll(1)
        if command == curses.KEY_UP:
            inputBox.moveCursor("u")
        if command == curses.KEY_DOWN:
            inputBox.moveCursor("d")
        if command == curses.KEY_LEFT:
            inputBox.moveCursor("l")
        if command == curses.KEY_RIGHT:
            inputBox.moveCursor("r")
        elif command > 0 and command < 256:
            inputBox.addText(chr(command)[0])


if __name__ == "__main__":
    from curses import wrapper
    try:
        wrapper(test)
    finally:
        pass
        #system("reset")